package com.yaodian100.ec.category.service.impl;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.yaodian100.core.admin.entity.Role;
import com.yaodian100.core.admin.entity.User;
import com.yaodian100.core.admin.entity.UserPermission;
import com.yaodian100.core.admin.entity.Permission.Type;
import com.yaodian100.core.admin.service.RoleService;
import com.yaodian100.core.admin.service.UserService;
import com.yaodian100.core.admin.utils.AdminHelper;
import com.yaodian100.core.common.dao.impl.CommonCriteria;
import com.yaodian100.core.common.dao.impl.CriteriaInRlike;
import com.yaodian100.core.common.exception.CoreException;
import com.yaodian100.core.common.service.BaseManager;
import com.yaodian100.core.common.service.impl.DomainServiceImpl;
import com.yaodian100.core.common.utils.ServerValue;
import com.yaodian100.ec.category.entity.Category;
import com.yaodian100.ec.category.service.CategoryService;
import com.yaodian100.ec.product.service.ProductService;

public class CategoryServiceImpl extends DomainServiceImpl<Category> implements CategoryService {
	@Resource
	private BaseManager baseMgr;
	@Resource
	private ProductService productService;
	@Autowired
	private UserService userService;
	@Autowired
	private RoleService roleService;
	private final String STRING_SYMBOL = "/";

	@Override
	public List<Category> getAvailableCategory() throws CoreException {
		String[] sortOrder = { "level", "categoryPath", "isPromotion" };
		CommonCriteria commcriteria = new CommonCriteria();
		commcriteria.addEq("isVisible", "Y");
		commcriteria.addEq("isDelete", "N");
		commcriteria.addLe("startDate", new Date());
		commcriteria.addGe("endDate", new Date());
		// CriteriaInRlike critInRlike = mergeCritInRlike(commcriteria);// 分線維護權限檢核
		return getDao().getList(commcriteria, sortOrder);
	}

	@Override
	public List<Category> getSideBarAvailableCategory() throws CoreException {
		Object[] categoryList = baseMgr.queryByHql("from Category where "
				+ " isVisible='Y' and isDelete='N'  and  endDate > sysdate and startDate<=Sysdate order by "
				+ "level asc ,decode(isBrand||isPromotion,'YN',10000,0)+decode(isBrand||isPromotion,'YY',20000,0)+ "
				+ "decode(isBrand||isPromotion,'NY',30000,0)+showSeq asc", new Object[] {});
		List<Category> cList = new ArrayList<Category>();
		if (categoryList != null) {
			for (Object obj : categoryList) {
				Category p = (Category) obj;
				cList.add(p);
			}
		}
		return cList;
	}

	@Override
	public List<Category> getAvailableChild(Long parentId) throws CoreException {
		Object[] categoryList = baseMgr.queryByHql("from Category where parentId = '" + parentId + "' "
				+ "and isVisible='Y' and isDelete='N'  and  endDate > sysdate " + mergeHqlInRlike(parentId) + " order by "
				+ "decode(isBrand||isPromotion,'YN',10000,0)+ " + "decode(isBrand||isPromotion,'YY',20000,0)+ "
				+ "decode(isBrand||isPromotion,'NY',30000,0)+showSeq ", new Object[] {});
		List<Category> cList = new ArrayList<Category>();
		if (categoryList != null) {
			for (Object obj : categoryList) {
				Category p = (Category) obj;
				cList.add(p);
			}
		}
		return cList;
	}

	@Override
	public List<Category> getVisibleChild(Long parentId) throws CoreException {
		CommonCriteria commcriteria = new CommonCriteria();
		commcriteria.addEq("parentId", parentId);
		commcriteria.addEq("isVisible", "Y");
		commcriteria.addLe("startDate", new Date());
		commcriteria.addGe("endDate", new Date());
		CriteriaInRlike critInRlike = mergeCritInRlike(commcriteria);// 分線維護權限檢核
		return getDao().getList(critInRlike, new String[] { "isBrand asc", "isPromotion asc", "showSeq asc" });
	}

	@Override
	public List<Category> getAvailableSameLevelCategory(Long parentId, String level) throws CoreException {
		CommonCriteria commcriteria = new CommonCriteria();
		commcriteria.addEq("parentId", parentId);
		commcriteria.addEq("level", level);
		commcriteria.addEq("isVisible", "Y");
		commcriteria.addEq("isDelete", "N");
		commcriteria.addLe("startDate", new Date());
		commcriteria.addGe("endDate", new Date());
		return getDao().getList(commcriteria, new String[] { "isBrand asc", "isPromotion asc", "showSeq asc" });

	}

	@Override
	public Category getCategoryById(Long categoryid) throws CoreException {
		CommonCriteria commcriteria = new CommonCriteria();
		commcriteria.addEq("id", categoryid);
		CriteriaInRlike critInRlike = mergeCritInRlike(commcriteria);// 分線維護權限檢核
		Category category = getDao().getSingle(critInRlike, null);
		if (null != category) {
			return category;
		} else {
			return null;
		}
	}

	@Override
	public Category getCategoryByName(String name) throws CoreException {
		CommonCriteria commcriteria = new CommonCriteria();
		commcriteria.addEq("name", name);
		List<Category> l = getDao().getList(commcriteria, new String[] { "id desc" });
		if (null != l && l.size() > 0) {
			return l.get(0);
		}
		return null;
	}

	@Override
	public List<Object[]> getCategoryLevelBottom(Long bottomId) throws CoreException {
		StringBuilder sb = new StringBuilder();
		sb.append("SELECT category_level,lpad(' ',2*(level-1)) || category_name,category_path,category_id,level  ");
		sb.append("FROM ec_category_main ");
		sb.append("start with category_id = ? CONNECT BY prior parent_id = category_id order by level desc");
		List attrs = new ArrayList();
		attrs.add(bottomId);
		return getDao().getSQLQueryByList(sb.toString(), attrs, 0, -1);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.category.service.CategoryService#getCategoryLevel(java.lang.Long)
	 */
	@Override
	public List<Object[]> getCategoryLevelTop(Long parentId) throws CoreException {
		StringBuilder sb = new StringBuilder();
		sb.append("SELECT category_level,lpad(' ',2*(level-1)) || category_name,category_path,category_id,level ");
		sb.append("FROM ec_category_main ");
		sb.append("start with parent_id = ? CONNECT BY prior category_id = parent_id");
		List attrs = new ArrayList();
		attrs.add(parentId);
		return getDao().getSQLQueryByList(sb.toString(), attrs, 0, -1);
	}

	@Override
	public List<Category> getChild(Long parentId) throws CoreException {
		StringBuffer sb = new StringBuffer();
		sb.append("from Category where parentId = '" + parentId + "' and isDelete='N' ");
		sb.append(mergeHqlInRlike(parentId));// 分線維護權限檢核
		sb.append(" order by decode(isBrand||isPromotion,'YN',10000,0) + ");
		sb.append("decode(isBrand||isPromotion,'YY',20000,0) + decode(isBrand||isPromotion,'NY',30000,0) + showSeq ");
		Object[] categoryList = baseMgr.queryByHql(sb.toString(), new Object[] {});
		List<Category> cList = new ArrayList<Category>();
		if (categoryList != null) {
			for (Object obj : categoryList) {
				Category p = (Category) obj;
				cList.add(p);
			}
		}
		sb.setLength(0);
		return cList;
	}

	@Override
	public String makeCategorieURL(Long categoryId, boolean addLink) throws CoreException {
		Category category;
		StringBuffer url = new StringBuffer();
		category = getCategoryNonePermission(categoryId);
		List<Object[]> catPath = getCategoryLevelBottom(category.getId());
		for (int i = 0; i < catPath.size(); i++) {
			Object[] ctry = catPath.get(i);

			String catId = "";
			String catName = "";
			for (int j = 0; j < ctry.length; j++) {
				switch (j) {
				case 1:// category name
					catName = String.valueOf(ctry[j]).trim();
					break;
				case 3:// category id
					catId = String.valueOf(ctry[j]);
					break;
				}
			}
			if (addLink) {
				url.append("<a href=\"").append(ServerValue.getFrontHostname()).append(ServerValue.getFrontContextPath())
						.append("/category/category.do?z=").append(catId).append("\" target=_blank>");
			}
			url.append(catName);
			if (addLink) {
				url.append("</a>");
			}
			if (i != catPath.size() - 1) {
				url.append(" &gt; ");
			}
		}
		return url.toString();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.yaodian100.ec.category.service.CategoryService#getAvailableCategory(java.lang.Long)
	 */
	@Override
	public Category getAvailableCategory(Long categoryId) throws CoreException {
		return getAvailableCategory(categoryId, true);
	}

	@Override
	public Category getAvailableCategoryNonePermission(Long categoryId) throws CoreException {
		return getAvailableCategory(categoryId, false);
	}

	Category getAvailableCategory(Long categoryId, boolean permission) throws CoreException {
		CommonCriteria commcriteria = new CommonCriteria();
		commcriteria.addEq("id", categoryId);
		commcriteria.addEq("isDelete", "N");
		commcriteria.addLe("startDate", new Date());
		commcriteria.addGe("endDate", new Date());
		if (permission) {
			CriteriaInRlike critInRlike = mergeCritInRlike(commcriteria);// 分線維護權限檢核
			return getDao().getSingle(critInRlike, null);
		} else {
			return getDao().getSingle(commcriteria, null);
		}
	}

	@Override
	@Transactional(readOnly = false)
	public Category save(Category entity) throws CoreException {
		entity = super.save(entity);
		if (0 == entity.getParentId()) {
			entity.setCategoryPath(entity.getId().toString());
		} else {
			Category parent = get(entity.getParentId());
			entity.setCategoryPath(parent.getCategoryPath() + STRING_SYMBOL + entity.getId());
		}
		entity = super.update(entity);
		// (目前僅level 0會做此修改)
		if ("0".equals(entity.getLevel().trim())) {
			User user = AdminHelper.getUser();
			if (StringUtils.equalsIgnoreCase("N", entity.getIsVisible())) {// 館設定為不顯示，底下的分類同時異動為不顯示
				// update Category isVisible='N' 線、父、子
				baseMgr.executeHql("update Category set isVisible = 'N',modifyDate = sysdate, " + "modifyUser = '"
						+ user.getUsername() + "'" + " where categoryPath like '" + entity.getCategoryPath() + "/%'",
						new Object[] {});
			}
			if (StringUtils.equalsIgnoreCase("Y", entity.getIsDelete())) {
				// update Category isDelete='Y' 線、父、子
				baseMgr.executeHql("update Category set isDelete = 'Y',modifyDate = sysdate, " + "modifyUser = '"
						+ user.getUsername() + "'" + " where categoryPath like '" + entity.getCategoryPath() + "/%'",
						new Object[] {});
				// delete ProductCategory 線、父、子
				baseMgr.executeHql("delete from ProductCategory where categoryPath like '" + entity.getCategoryPath() + "/%'",
						new Object[] {});
			}
			Role role = roleService.get(entity.getId().toString(), Role.Type.CATEGORY);
			if (null == role) {// 建立role
				Role r = new Role(entity.getId().toString(), entity.getName() + "(" + entity.getId().toString() + ")",
						Role.Type.CATEGORY);
				roleService.save(r);
			} else {
				if (StringUtils.equalsIgnoreCase("Y", entity.getIsDelete())) {// 館刪除時，刪除role
					roleService.delete(role);
				} else {// 存檔時，異動role name
					role.setDescription(entity.getName() + "(" + entity.getId().toString() + ")");
					roleService.update(role);
				}
			}
		}
		return entity;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.yaodian100.ec.category.service.CategoryService#updateCategoryAndProductCategory(com.yaodian100.ec.category.
	 * entity.Category)
	 */
	@Override
	@Transactional(readOnly = false)
	public Category updateCategoryAndProductCategory(Category category) {
		// update
		if (null != category.getId()) {
			category = update(category);
			String categoryName = category.getName().contains("'") ? category.getName().replaceAll("'", "''") : category
					.getName();
			if (category.getIsEndnode().equals("Y")) {
				List<Category> childs = getChild(category.getId());
				User user = AdminHelper.getUser();
				if (childs.size() > 0) {
					List<Long> childIds = new ArrayList<Long>();
					for (Category child : childs) {
						childIds.add(child.getId());
					}
					// 館設定為不顯示，底下的分類同時異動為不顯示(目前僅level 0會做此修改)
					if ("0".equals(category.getLevel().trim()) && StringUtils.equalsIgnoreCase("N", category.getIsVisible())) {
						// update Category isVisible='N' 子分類
						baseMgr.executeHql("update Category set isVisible = 'N',modifyDate = sysdate, " + "modifyUser = '"
								+ user.getUsername() + "'" + " where categoryId in ( "
								+ ArrayUtils.toString(childIds).replace("[", "").replace("]", "") + " )", new Object[] {});
					}
					// update ec_product_main
					baseMgr.executeHql("update Product set mainCategoryID = " + category.getId().toString()
							+ ",modifyDate = sysdate ,modifyUser = '" + user.getUsername() + "' " + "where mainCategoryID in ( "
							+ ArrayUtils.toString(childIds).replace("[", "").replace("]", "") + " )", new Object[] {});
					logger.info("step2 update ec_product_main");
					// update ec_product_category
					baseMgr.executeHql("update ProductCategory set categoryId = " + category.getId() + " , categoryPath = '"
							+ category.getCategoryPath() + "',categoryName = '" + categoryName + "',modifyDate = sysdate ,"
							+ "modifyUser = '" + user.getUsername() + "' where categoryId in ( "
							+ ArrayUtils.toString(childIds).replace("[", "").replace("]", "") + " )", new Object[] {});
					logger.info("step3 update ec_product_category");
					// update category
					baseMgr.executeHql("update Category set isDelete = 'Y',modifyDate = sysdate, " + "modifyUser = '"
							+ user.getUsername() + "'" + " where id in ( "
							+ ArrayUtils.toString(childIds).replace("[", "").replace("]", "") + " )", new Object[] {});
					logger.info("step4 update category isDelete = 'Y'");
					// delete 重複資料
					baseMgr.executeHql(
							"delete from ProductCategory where id in (select max(pc.id) from ProductCategory pc where pc.categoryId = '"
									+ category.getId() + "' group by pc.productId, pc.categoryId having count(pc) > 1)", new Object[] {});
					logger.info("step5  delete 重複資料");
				} else {
					baseMgr.executeHql("update ProductCategory set categoryName = '" + categoryName + "',modifyDate = sysdate ,"
							+ "modifyUser = '" + user.getUsername() + "' where categoryId = " + category.getId().toString(),
							new Object[] {});
				}
			}
		} else {
			String categoryName = category.getName().contains("'") ? category.getName().replaceAll("'", "''") : category
					.getName();
			if (category.getIsEndnode().equals("Y")) {
				// get parent category
				Category parent = get(category.getParentId());
				parent.setIsEndnode("N");
				update(parent);
				logger.info("step1 update parent isendnode = 'N'");
				save(category);
				logger.info("step2 save category");
				User user = AdminHelper.getUser();
				// update ec_product_main
				baseMgr.executeHql("update Product set mainCategoryID = " + category.getId().toString()
						+ ",modifyDate = sysdate ,modifyUser = '" + user.getUsername() + "' " + " where mainCategoryID = '"
						+ parent.getId() + "'", new Object[] {});
				logger.info("step3 update ec_product_main");
				// update ec_product_category
				baseMgr
						.executeHql("update ProductCategory set categoryId = " + category.getId() + " , categoryPath = '"
								+ category.getCategoryPath() + "',categoryName = '" + categoryName + "' ,modifyDate = sysdate ,"
								+ "modifyUser = '" + user.getUsername() + "' where categoryId =  '" + parent.getId() + "'",
								new Object[] {});
				logger.info("step4 ec_product_category");
			}
		}
		return category;
	}

	/**
	 * 分線維護權限檢核
	 * 
	 * @param commcriteria
	 * @return
	 */
	CriteriaInRlike mergeCritInRlike(CommonCriteria commcriteria) {
		CriteriaInRlike critInRlike = null;
		boolean level0 = false;
		User user = AdminHelper.getUser();
		if (null != user) {
			if (null == commcriteria) {
				commcriteria = new CommonCriteria();
			}
			critInRlike = new CriteriaInRlike(commcriteria);
			// 由傳入條件的level判斷是否為root
			if (MapUtils.isNotEmpty(critInRlike.getEq()) && critInRlike.getEq().containsKey("level")
					&& critInRlike.getEq().get("level").equals("0")) {
				level0 = true;
			}
			// 由傳入條件的id判斷是否為root
			if (MapUtils.isNotEmpty(critInRlike.getEq()) && critInRlike.getEq().containsKey("id")) {
				Category category = get(critInRlike.getEq().get("id"));
				if (null != category) {
					if ("0".equals(category.getLevel())) {
						level0 = true;
					}
				}
			}
			// 若 user 是 PM部門, 檢核 product.category 的 orgnizationPath 是否合乎規定
			if (user.getPermissions(Type.CATEGORY).size() > 0) {
				List<Serializable> prs = new ArrayList<Serializable>();
				for (UserPermission up : user.getPermissions(Type.CATEGORY).values()) {
					if (level0) {
						prs.add(up.getPermissionCode());
					} else {
						prs.add(up.getPermissionCode() + STRING_SYMBOL);
					}
				}
				critInRlike.addInRlike("categoryPath", prs);
			}
		} else {
			if (null == commcriteria) {
				commcriteria = new CommonCriteria();
			}
			critInRlike = new CriteriaInRlike(commcriteria);
		}
		return critInRlike;
	}

	/**
	 * 分線維護權限檢核
	 * 
	 * @param parentId
	 * @return
	 */
	String mergeHqlInRlike(Long parentId) {
		String premissString = "";
		String symbol = "";
		if (null != parentId && parentId.intValue() > 0) {
			symbol = STRING_SYMBOL;
		}
		StringBuffer sb = new StringBuffer();
		User user = AdminHelper.getUser();
		if (null != user) {
			// 若 user 是 PM部門, 檢核 product.category 的 orgnizationPath 是否合乎規定
			int permissionSize = user.getPermissions(Type.CATEGORY).size();
			if (permissionSize > 0) {
				sb.append("and ( ");
				int i = 0;
				for (UserPermission up : user.getPermissions(Type.CATEGORY).values()) {
					sb.append("categoryPath like '").append(up.getPermissionCode()).append(symbol).append("%'");
					if (i != permissionSize - 1) {
						sb.append(" or ");
					}
					i++;
				}
				sb.append(" ) ");
				premissString = sb.toString();
				sb.setLength(0);
			}
		}
		return premissString;
	}

	public ProductService getProductService() {
		return productService;
	}

	public void setProductService(ProductService productService) {
		this.productService = productService;
	}

	@Override
	public List<Category> getList(int firstResult, int maxResults, CommonCriteria criteria, String[] sortOrder)
			throws CoreException {
		CriteriaInRlike critInRlike = mergeCritInRlike(criteria);// 分線維護權限檢核
		return super.getList(firstResult, maxResults, critInRlike, sortOrder);
	}

	@Override
	public List<Category> getListNonePermission(int firstResult, int maxResults, CommonCriteria criteria,
			String[] sortOrder) throws CoreException {
		return super.getList(firstResult, maxResults, criteria, sortOrder);
	}

	@Override
	public Number getListSize(CommonCriteria criteria) throws CoreException {
		CriteriaInRlike critInRlike = mergeCritInRlike(criteria);// 分線維護權限檢核
		return super.getListSize(critInRlike);
	}

	@Override
	public Category get(Serializable oid) throws CoreException {
		Category category = super.get(oid);
		// 分線維護權限檢核
		User user = AdminHelper.getUser();
		if (null != user) {
			// 若 user 是 PM部門, 檢核 product.category 的 orgnizationPath 是否合乎規定
			if (user.getPermissions(Type.CATEGORY).size() > 0) {
				if (StringUtils.isNotBlank(category.getRootId())) {
					if (!user.getPermissions(Type.CATEGORY).keySet().contains("CATEGORY_" + category.getRootId())) {
						category = null;
					}
				}
			}
		}
		return category;
	}

	// 沒卡user權限
	public Category getCategoryNonePermission(Serializable oid) throws CoreException {
		return super.get(oid);
	}

	/**
	 * 取得分类毛利率
	 */
	@Override
	public BigDecimal getGrossProfitByPath(String category_path) {
		if (StringUtils.isBlank(category_path)) {
			return null;
		}
		String[] cids = category_path.split("/");
		List<Long> cidL = new ArrayList<Long>();
		for (String cid : cids) {
			cidL.add(Long.parseLong(cid));
		}
		CommonCriteria criteria = new CommonCriteria();
		criteria.addIn("id", cidL);
		criteria.addNe("grossProfit", null);
		List<Category> catTemp = getListNonePermission(0, -1, criteria, new String[] { "level desc" });
		if (null != catTemp && catTemp.size() != 0) {
			return catTemp.get(0).getGrossProfit();
		}
		return null;
	}
}
